use crate::mimalloc::{*,types::*,internal::*,track::*,atomic::*};
use std::{borrow::Borrow, rc::Rc};
use std::cell::RefCell;
use crate::{mi_assert,MI_UNUSED};

pub type HeapPageVisitorFun = fn(heap: &MiHeap, pq: &MiPageQueue, page: &MiPage, arg1: Option<&dyn std::any::Any>, arg2: Option<&dyn std::any::Any>) -> bool;
impl MiHeap {
    // Visit all pages in a heap; returns `false` if break was called
    pub fn mi_heap_visit_pages<F>(&self, fn_vis: F, arg1: Option<&dyn std::any::Any>, arg2: Option<&dyn std::any::Any>) -> bool
    where
        F: Fn(&MiHeap, &MiPageQueue, &MiPage, Option<&dyn std::any::Any>, Option<&dyn std::any::Any>) -> bool,
    {
        if self.page_count == 0 {
            return false;
        }

        // Debug assertion
        let total = self.page_count;
        let mut count = 0;

        // Visit all pages
        for pq_iter in self.pages.iter() {
            let pq: &mut MiPageQueue = unsafe {
                pq_iter.as_mut().unwrap() 
            };
            let mut next_page = None;
            let mut page = pq.first.clone();
            while let Some(ref page_rc) = page {
                let mut page_in = page_rc;
                let next = page_in.as_ref().borrow().next.clone(); // Save next in case the page gets removed from the queue

                // In the original C, we have a mi_assert_internal; in Rust we could use debug_assert!
                //mi_assert!(mi_page_heap(&page).unwrap() == Some(self));

                // Debug count
                if MI_DEBUG_GTONE {
                    count += 1;
                }

                // Call the visitor function, and break early if it returns false
                if !fn_vis(self, pq, &page_in.as_ref().borrow(), arg1, arg2) {
                    return false;
                }
                // Move to the next page after the visitor function call
                if let Some(next_page_rc) = next {
                    next_page = Some(next_page_rc.clone()); 
                    
                }else{
                    break;
                }
                // If there's no next page, break the loop
                page = next_page; 
            }
        }

        //#[cfg(debug_assertions)]
        //mi_assert!(count == total);

        true
    }
}


/* -----------------------------------------------------------
  "Collect" pages by migrating `local_free` and `thread_free`
  lists and freeing empty pages. This is done when a thread
  stops (and in that case abandons pages if there are still
  blocks alive)
----------------------------------------------------------- */
#[derive(Debug, Clone, Copy)]
pub enum MiCollect {
    MI_NORMAL,
    MI_FORCE,
    MI_ABANDON,
}

impl MiHeap {
    pub fn mi_heap_page_collect(
        &self,
        pq: &MiPageQueue,
        page: &mut MiPage,
        arg_collect: &MiCollect,
        _arg2: Option<&dyn std::any::Any>,
    ) -> bool {
        MI_UNUSED!(_arg2);

        let collect = *arg_collect;
        

        true
        
    }
}
